/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is COID http service.
 *
 * The Initial Developer of the Original Code is
 * PosAm.
 * Portions created by the Initial Developer are Copyright (C) 2005
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Brano Kemen
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */
 
#ifndef __COID_SERVICES_WEBTALK_CORE__HEADER_FILE__
#define __COID_SERVICES_WEBTALK_CORE__HEADER_FILE__

#include "coid/comm/segarray.h"
#include "coid/comm/binstream/filestream.h"
#include "coid/comm/metastream/fmtstreamcxx.h"
#include "smiley.h"

////////////////////////////////////////////////////////////////////////////////
class WebtalkCore
{
public:
    struct Line
    {
        uint _from;
        uint _to;
        charstr _text;
    };

    struct User
    {
        uint uqid;
        charstr name;
        uint cnt;

        User() { cnt=0; uqid=UMAX32; }

        bool operator < (const token& aname) const      { return name < aname; }
        bool operator == (const token& aname) const     { return name == aname; }
    };

    comm_mutex _mutex;

    operator token() const      { return _board; }

protected:

    charstr _board;

    uint _nlastlinesaved;

    uint _nlinesmax;
    segarray<Line> _lines;

    typedef segarray<Line>::ptr     seg_ptr;

    dynarray<User> _users;
    uint _usrchng;

    dynarray<Smiley> _smiles;
    int _smiconf;

public:

    WebtalkCore()
    {
        _nlastlinesaved = 0;
        _nlinesmax = 1024;
        _lines.set_segsize(1024);   //1k pages

        _usrchng = 0;
        _smiconf = 0;
    }

    void set_board( const token& board )    { _board = board; }

    bool is_smiley_configured() const       { return _smiconf != 0; }

    opcd conf_smileys( charstr& fpath )
    {
        _smiconf = 1;

        fpath << "?re";
        fileiostream cfg(fpath);
        if( !cfg.is_open() )  return ersIO_ERROR;

        charstr code;
        charstr path;
        fmtstreamcxx fmt(cfg);
        
        opcd e;
        for(; 0 == fmt.read_type( &code ); )
        {
            e = fmt.read_type( &path );
            if(e)  return e;

            Smiley* ps = _smiles.add_sortT(code);
            ps->code.takeover(code);
            ps->path << path;
        }

        return 0;
    }

    const dynarray<Smiley>& get_smileys() const         { return _smiles; }


    opcd add( uint who, const token& towho, charstr& text )
    {
        uint usr = UMAX32;
        if( !towho.is_empty() ) {
            usr = find_user(towho);
            if( usr == UMAX32 )
                return ersINVALID_NAME;
        }

        add( who, usr, text );
        return 0;
    }

    void add( uint who, uint towho, charstr& text )
    {
        seg_ptr old;
        if( _lines.size() >= _nlinesmax )
            _lines.first(old);

        Line* p = _lines.push_item();
        if( old.is_valid() )
            p->_text.swap( old->_text );

        p->_from = who;
        p->_to = towho;
        p->_text.swap(text);

        if( _lines.size() > _nlastlinesaved + 10 )
            save();
    }

    uint read( uint who, uint idx, dynarray<token>& lst, uint* usrchng )
    {
        seg_ptr ref;
        uint n=10;

        _lines.get_ptr( idx, ref );
        for(; ref.is_valid() && n>0; ++ref )
        {
            const Line& lin = *ref;
            if( lin._text.is_empty() )  continue;
            if( lin._to == UMAX32 || lin._to == who || lin._from == who )
            {
                *lst.add() = lin._text;
                --n;
            }
        }

        *usrchng = _usrchng;
        return ref.index();
    }

    void save()
    {
    }

    uint get_usrchng() const            { return _usrchng; }
    uints get_current_pos() const       { return _lines.size(); }

    bool add_user( const token& name, uint uqid )
    {
        uints k = _users.lower_boundT(name);
        if( k < _users.size()  &&  _users[k] == name )
        {
            ++_users[k].cnt;
            return false;
        }
        else
        {
            User* p = _users.ins(k);
            p->name = name;
            p->uqid = uqid;
            p->cnt = 1;
            ++_usrchng;
            return true;
        }
    }

    bool del_user( const token& name, uint uqid )
    {
        //dynarray_del_sort( _users, name );
        uints p = _users.lower_boundT(name);
        uints n = _users.size();
        if( p<n  &&  _users[p].name == name )
        {
            if( --_users[p].cnt == 0 ) {
                _users.del(p);
                ++_usrchng;
                return true;
            }
        }

        return false;
    }

    uint find_user( const token& name )
    {
        uints pos = _users.lower_boundT(name);
        if( pos >= _users.size()  ||  _users[pos].name != name )
            return UMAX32;
        return _users[pos].uqid;
    }

    void get_usrlist( charstr& dst ) const
    {
        for( uints i=0; i<_users.size(); ++i )
            dst << _users[i].name << char(';');
    }
};

#endif //__COID_SERVICES_WEBTALK_CORE__HEADER_FILE__
